package com.caijb.juc;

import java.util.concurrent.locks.StampedLock;

public class StampedLockDemo {
    private double x, y;
    private final StampedLock stampedLock = new StampedLock();

    // 写操作
    public void move(double deltaX, double deltaY) {
        long stamp = stampedLock.writeLock();
        try {
            x += deltaX;
            y += deltaY;
            System.out.println("写操作: x=" + x + ", y=" + y);
        } finally {
            stampedLock.unlockWrite(stamp);
        }
    }

    // 悲观读操作
    public double distanceFromOrigin() {
        long stamp = stampedLock.readLock();
        try {
            return Math.sqrt(x * x + y * y);
        } finally {
            stampedLock.unlockRead(stamp);
        }
    }

    // 乐观读操作
    public void showCoordinates() {
        long stamp = stampedLock.tryOptimisticRead();
        double currentX = x, currentY = y;

        // 验证乐观读期间是否有写操作
        if (!stampedLock.validate(stamp)) {
            // 如果有写操作，升级为悲观读
            stamp = stampedLock.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                stampedLock.unlockRead(stamp);
            }
        }
        System.out.println("坐标: x=" + currentX + ", y=" + currentY);
    }

    // 锁转换示例
    public void moveIfOrigin() {
        long stamp = stampedLock.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                // 转换为写锁
                long writeStamp = stampedLock.tryConvertToWriteLock(stamp);
                if (writeStamp != 0L) {
                    stamp = writeStamp;
                    x = 1.0;
                    y = 1.0;
                    System.out.println("坐标从原点移动到(1,1)");
                    break;
                } else {
                    // 转换失败，释放读锁并获取写锁
                    stampedLock.unlockRead(stamp);
                    stamp = stampedLock.writeLock();
                }
            }
        } finally {
            stampedLock.unlock(stamp);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        StampedLockDemo demo = new StampedLockDemo();

        // 创建多个线程进行测试
        Thread writer = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                demo.move(1.0, 1.0);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        Thread reader1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                demo.showCoordinates();
                try {
                    Thread.sleep(150);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        Thread reader2 = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                double distance = demo.distanceFromOrigin();
                System.out.println("距离原点: " + distance);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        Thread converter = new Thread(() -> {
            demo.moveIfOrigin();
        });

        // 启动所有线程
        writer.start();
        reader1.start();
        reader2.start();
        converter.start();

        // 等待所有线程完成
        writer.join();
        reader1.join();
        reader2.join();
        converter.join();
    }
}
